JavaScript实现拼数字游戏

作者:陈广
日期:2018-4-9


拼数字游戏是在我的《C#程序设计基础教程与实训》这本书里数组这一章的一个例子,代码很精简。现在学 JavaScript,正好拿这个程序来练手。这一系列文章讲的是 TypeScript,就用一个 JavaScript 例子作为开头吧。先上效果再写代码。

玩游戏的时候需要注意,有一半的机会游戏是无法完成的,关于这一点在我的《数据结构 C#语言描述》这本书有详细描述和算法解决办法。此程序只是演示元素的动态创建,就不写那么周全了。

HTML文件

新建一个文件夹,命名为NumberGame,点右键用 vscode 打开。然后新建一个NumberGame.html文件。输入如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>拼数字游戏</title>
    <link rel="stylesheet" href="NumberGame.css">
</head>
<body>
    <div id="Container"></div>
    <button id="Button">开始游戏</button>
</body>
<script src="NumberGame.js"></script>
</html>

这里只有一个 div 和一个 button,九宫格本来应该有九个按钮,可以直接在 div 里写 HTML 创建。但是为了学习 JavaScript,这次使用 JavaScript 动态创建按钮并关联事件,包括 button 的事件。其实即使使用 JavaScript 动态创建,也有两种方式。第一种是使用 JavaScript 函数创建,这次准备使用这种方法创建。第二种是在 JavaScript 中拼揍 HTML 然后加到 div 中。这种方式准备在用 TypeScript 重写的时候使用。

CSS文件

新建一个NumberGame.css文件,使用如下代码:

body {
	text-align: center;
	background-color: #bbb;
}

#Container {
	position: relative;
	width: 240px;
	height: 240px;
	margin: 0 auto;
	margin-top: 20px;
	border: 5px solid darkgoldenrod;
	border-radius: 5px;
}

.NumBtn {
	position: absolute;
	background-color: tomato;
	color: azure;
	box-sizing: border-box;
	border: 1px solid #ccc;
	font-size: 50px;
	user-select: none;
}

#Button {
	margin-top: 20px;
	padding: 10px 20px;
    background: #A2B598;
    background: -webkit-gradient(linear, left top, left bottom, from(#BDD1B4), to(#A2B598));
    background: -moz-linear-gradient(-90deg, #BDD1B4, #A2B598);
    filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr='#BDD1B4', EndColorStr='#A2B598');
}

#Button:hover {
    background: #BDD1B4;
    background: -webkit-gradient(linear, left top, left bottom, from(#A2B598), to(#BDD1B4));
    background: -moz-linear-gradient(-90deg, #A2B598, #BDD1B4);
    filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr='#A2B598', EndColorStr='#BDD1B4');
}

#Button:active {
    background: #A2B598;
}

css不是我关注的重点,所以按钮随便上网找了个 CSS 套上去收工。这里我就不讲了。

JavaScript 文件

新建一个NumberGame.js文件,使用如下代码:

//全局变量
var btnArr = new Array(3); //装按钮的数组
var unRow = 0;
var unCol = 0;
//窗体载入事件
window.onload = function () {
    for (var i = 0; i < btnArr.length; i++) {
        btnArr[i] = new Array(3);
    }
    Create_div();
    //给开始游戏按钮绑定事件
    document.getElementById("Button").addEventListener("click", PlayGame);
}

function Create_div() {
    var container = document.getElementById("Container");
    for (var i = 0; i < 9; i++) {
        var btn = document.createElement("button"); //创建装数字的Div         

        btn.className = "NumBtn";
        //设置数字div边长
        var edgeLen = Math.floor((container.offsetWidth - 10) / 3);
        btn.style.height = edgeLen + "px";
        btn.style.width = edgeLen + "px";
        //设置数字div位置
        btn.style.left = (i % 3) * edgeLen + "px";
        btn.style.top = Math.floor(i / 3) * edgeLen + "px";
        btn.innerText = i + 1; //设置文本
        btn.style.lineHeight = edgeLen + "px"; //垂直居中
        //给每个加入div的按钮绑定事件
        btn.addEventListener("click", Btn_Click);
        container.appendChild(btn); //将按钮加入 div
        //加入数组
        btnArr[Math.floor(i / 3)][i % 3] = btn;
    }
}
//随机函数low表示最小随机值,high表示最大随机值
function randomBetween(low, high) {
    return Math.floor(Math.random() * (high - low + 1) + low);
}
//开始游戏方法,用于绑定开始游戏按钮
function PlayGame() {
    btnArr[unRow][unCol].style.display = "block";
    var nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (var i = 0; i < 8; i++) {
        var rmNum = randomBetween(i, 8);
        var temp = nums[i];
        nums[i] = nums[rmNum];
        nums[rmNum] = temp;
    }
    for (var i = 0; i < 9; i++) {
        btnArr[Math.floor(i / 3)][i % 3].innerText = nums[i];
    }
    var cover = randomBetween(0, 8);
    unRow = Math.floor(cover / 3);
    unCol = cover % 3;
    btnArr[unRow][unCol].style.display = "none";
}
//单击数字时的事件
function Btn_Click() {
    var row = this.offsetTop / 80;
    var col = this.offsetLeft / 80;
    if (Math.abs(row - unRow) + Math.abs(col - unCol) == 1) {
        var temp = btnArr[unRow][unCol].innerText;
        btnArr[unRow][unCol].innerText = btnArr[row][col].innerText
        btnArr[row][col].innerText = temp;
        btnArr[unRow][unCol].style.display = "block";
        btnArr[row][col].style.display = "none";
        unRow = row;
        unCol = col;
    }
    //判定是否游戏结束
    for (var i = 0; i < 9; i++) {
        if (btnArr[Math.floor(i / 3)][i % 3].innerText != i + 1) {
            break;
        }
        if (i == 8) {
            btnArr[unRow][unCol].style.display = "block";
            alert("闯关成功!");
        }
    }
}

这段代码主要演示了如何使用 JavaScript 动态加载 HTML 元素并绑定事件。关键点在于:

JavaScript 不支持二维数组,坑爹。好在可以模拟,这里也做了演示。算法这一块我就不讲了,不重点。